package cn.itcast.bos.web.action.base;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Controller;

import cn.itcast.bos.domain.base.Area;
import cn.itcast.bos.service.base.AreaServcie;
import cn.itcast.bos.utils.PinYin4jUtils;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
@ParentPackage("json-default")
@Namespace("/")
@Controller
@Scope("prototype")//表名  action 是多例的
public class AreaAction extends ActionSupport implements ModelDriven<Area>{
//模型驱动   获得页面数据
	private Area area = new Area();
	@Override
	public Area getModel() {
		return area;
	}
	//注入业务层 对象
	@Autowired
	private AreaServcie areaServcie;
	
	//接收上传的文件   通过struts2在配置文件 Struts-default.xml中定义了拦截器fileUpload来完成
	private File file;	 //注意:File导包是io中的  而不是struts2中的
	public void setFile(File file) {
		this.file = file;
	}
	private String fileFileName;//获得文件名称  注意:这里的文件名称是全路径名称
	public void setFileFileName(String fileFileName) {
		this.fileFileName = fileFileName;
	}
	//批量导入 区域 数据
	/*思路:1.创建一个集合将area存放在里面;
	 * 2.编写解析代码逻辑
	 * 	2.1.加载Excel文件对象; 
	 *		 注意:其实获得的是所有sheet对象的一个数组
	 * 	2.2.读取里面的一个sheet,根据索引(是页面的位置吗?)
	 * 		注意: 这里sheet其实是sheet里面每行数据对象的一个数组
	 * 	2.3.遍历sheet(即每行数据的数组) ,将每行数据封装到 Area对象中,并将area存到集合中
	 * 		注意:每一行数据对应 一个Area对象
	 * 3.调用业务层方法
	 */
	@Action(value="area_batchImport")
	public String batchImport() throws FileNotFoundException, IOException{
		//1.定义一个集合  来存放 area对象
		List<Area> areas = new ArrayList<Area>();
		//2.解析代码    基于.xls格式解析HSSF
		//2.1.加载Excel文件对象
		HSSFWorkbook hssfWorkbook =   new HSSFWorkbook(new FileInputStream(file));
		//2.2读取里面我们想要的 sheet对象
		HSSFSheet sheet = hssfWorkbook.getSheetAt(0);
		//2.3读取sheet中的每一行
		for (Row row : sheet) {
			//一行数据对应一个 Area对象
			if(row.getRowNum()==0){
				continue; //第一行是  每列的名称 ,不需要   跳过
			}
			//跳过 空行
			if(row.getCell(0)==null ||
				StringUtils.isBlank(row.getCell(0).getStringCellValue())	){
				System.out.println(row.getCell(0)+"###"+row.getCell(0).getStringCellValue());
				continue;
			}
			//将每行数据 封装到 Area对象中
			Area area = new Area();
			area.setId(row.getCell(0).getStringCellValue());
			area.setProvince(row.getCell(1).getStringCellValue());
			area.setCity(row.getCell(2).getStringCellValue());
			area.setDistrict(row.getCell(3).getStringCellValue());
			area.setPostcode(row.getCell(4).getStringCellValue());
			//使用Pinyin4j的工具类  生成 区域简码   城市编码 
			//简码:即 省市区名称的首字母组合的字符串
			//城市编码:即 市的汉字的拼音
			String province = area.getProvince();
			String city = area.getCity();
			String district = area.getDistrict();
			//由于简码中  不需要 '省'  '市'  '区'  的首字母  故需要截取原来的字符串
			province = province.substring(0,province.length()-1);
			city = city.substring(0, city.length()-1);
			district = district.substring(0, district.length()-1);
			//生成区域简码   
			String[] headString = PinYin4jUtils.getHeadByString(province+city+district);
			StringBuffer buffer = new StringBuffer();
			for (String string : headString) {
				buffer.append(string);
			}
			String shortcode =buffer.toString(); //获得  区域简码
			area.setShortcode(shortcode);//
			//生成 城市编码
			String citycode = PinYin4jUtils.hanziToPinyin(city, "");//""里面写分割内容,由于我们不需要分割符,故给个空字符串
			area.setCitycode(citycode);//获得城市编码
			
			//将封装好的 area 存到集合中
			areas.add(area);
		}
		//调用业务层
		areaServcie.saveBatch(areas);
		return NONE;
	}
	
	//#########################        强化后的   区域信息批量导入功能          ############################
	/*思路分析
	 * 功能实现:加载上传文件-->解析上传文件获得sheet对象(通过索引或name)-->循环遍历获得每一行的对象row(跳过第一行,空行)
	 * -->获得每一行每一个单元格的值并封装到区域对象area中(每一行数据代表一个区域对象)-->生成区域简码  城市简码-->生成将
	 * 区域对象存到集合中--->调用service执行保存操作
	 * 
	 * */
	@Action(value="area1_batchImport")
	public String batch1Import() {
		String msg="";
		try {
			// 创建一个集合 来存储区域对象 area
			List<Area> list = new ArrayList<Area>();

			Workbook workbook = null;
			// 根据文件名称后缀来判断文件格式,并赋不同的值 给workbook(完成了加载导入文件的功能)
			if (fileFileName.endsWith(".xls")) {// HssF解析Excel 97-2007格式(.xls)
				workbook = new HSSFWorkbook(new FileInputStream(file));
			} else if (fileFileName.endsWith(".xlsx")) {// XssF解析Excel
														// 2007以后的格式(.xlsx)
				workbook = new XSSFWorkbook(file);
			}
			// 读取一个sheet 既可以根据索引 也可以根据名称
			Sheet sheet = workbook.getSheetAt(0);
			// 读取sheet中的每一行
			for (Row row : sheet) {
				// 一行数据对应 一个区域 对象 area 并需要跳过 第一行 空白行
				if (row.getRowNum() == 0) {// 跳过第一行
					continue;
				}
				if (row.getCell(0) == null
						|| StringUtils.isBlank(row.getCell(0)
								.getStringCellValue())) {
					continue;
				}
				// 将每行数据 封装到 Area对象中
				Area area = new Area();
				area.setId(row.getCell(0).getStringCellValue());
				area.setProvince(row.getCell(1).getStringCellValue());
				area.setCity(row.getCell(2).getStringCellValue());
				area.setDistrict(row.getCell(3).getStringCellValue());
				area.setPostcode(row.getCell(4).getStringCellValue());

				// 使用pinyin4j完成 区域编码 城市简码
				String province = area.getProvince();
				String city = area.getCity();
				String district = area.getDistrict();
				// 由于区域简码 中 不含"省" "市" 的字母 故需对原来的进行截取
				province = province.substring(0, province.length() - 1);
				city = city.substring(0, city.length() - 1);
				district = district.substring(0, district.length() - 1);
				// 生成区域简码
				String[] headArray = PinYin4jUtils.getHeadByString(province
						+ city + district);
				StringBuffer buffer = new StringBuffer();
				for (String headStr : headArray) {
					buffer.append(headStr);
				}
				String shortcode = buffer.toString();
				area.setShortcode(shortcode.toString());
				// 生成 城市编码
				String citycode = PinYin4jUtils.hanziToPinyin(city);
				area.setCitycode(citycode);

				// 将 区域对象 area 存到集合中
				list.add(area);
			}
			//调用业务层
			areaServcie.saveBatch(list);
			workbook.close();
			//int i = 4/0; //测试上传失败测试
			msg="上传成功  ! ! ! ";
		} catch (Exception e) {
			msg = "上传失败 !!!";
			e.printStackTrace();
		}
		//中文乱码处理
		ServletActionContext.getResponse().setCharacterEncoding("UTF-8");
		//将信息通过response写回页面
		try {
			ServletActionContext.getResponse().getWriter().write(msg);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return NONE;
	}
	
	
	//&&&&&&&&&&&&&&&&&&&&&& 批量导出功能的实现 &&&&&&&&&&&&&&&&&&&&&&&
	/** 
	 * 导出方法:这里采用文档注释将来可以抽取生成javaDOC 文档.api
	 * 
	 */
	@Action(value = "area_export")
	public String export(){
		//导出的拓展:当数据很多时如何导出(创建多个sheet)
		try{
			//1.查询所有数据
			List<Area> areas  = new ArrayList<Area>();
			for (int i = 0; i <100000; i++) {
				areas.add(new Area(""+i,"陕西省"+i,"西安市"+i,"未央区"+i,"","",""));
			}
			//2.将集合数据写入excel中
			//2.1创建workBook
			HSSFWorkbook workbook = new HSSFWorkbook();
			/**
			 * 计算一共多少个sheet,每页显示5000条    一个sheet最多存65535行数据   一个文件可以最多有32768个sheet
			 * 目前一共有100000条数据,即需要100000行,设置每一个sheet 5000
			 */
			
			int totalNum = (int) Math.ceil(areas.size()*1.0/5000) ;//totalNum表示:sheet的个数
			for(int i=0 ; i<totalNum;i++){
				//2.2创建一个 sheet   并设置sheet的名称
				HSSFSheet sheet = workbook.createSheet("区域数据"+i);
				//2.3创建表头行
				HSSFRow firstRow = sheet.createRow(0);
				//创建表头行的单元格
				firstRow.createCell(0).setCellValue("区域编码");
				firstRow.createCell(1).setCellValue("省份");
				firstRow.createCell(2).setCellValue("城市");
				firstRow.createCell(3).setCellValue("区域");
				firstRow.createCell(4).setCellValue("邮编");
				firstRow.createCell(5).setCellValue("简码");
				firstRow.createCell(6).setCellValue("城市编码");
				//2.4添加数据,遍历list,创建row,cell
				int start = i*5000; //集合开始遍历的角标
				int end = (i+1)*5000;//集合结束遍历的角标
				if(end>=areas.size()){//end不该集合长度
					end=areas.size();
				}
				//遍历集合  
				for (int j = start; j < end; j++) { //写每一个sheet的信息
					//创建当前行的  下一行
					HSSFRow row = sheet.createRow(sheet.getLastRowNum()+1);
					Area area = areas.get(j);
					row.createCell(0).setCellValue(area.getId());
					row.createCell(1).setCellValue(area.getProvince());
					row.createCell(2).setCellValue(area.getCity());
					row.createCell(3).setCellValue(area.getDistrict());
					row.createCell(4).setCellValue(area.getPostcode());
					row.createCell(5).setCellValue(area.getShortcode());
					row.createCell(6).setCellValue(area.getCitycode());
				}
			}
			//3.文件下载
			/**
			 * 文件下载:两个头   一个流
			 * 两个头:
			 * content-Type:
			 * content-disposition:指定客户端打开文件的方式
			 * 	默认:inline ,在浏览器中打开
			 * 	下载:attachment;filename=XXX
			 * 一个流:
			 * response输出流;response.getOutputStream()
			 */
			//4.将workbook写入流
			HttpServletResponse response = ServletActionContext.getResponse();
			String filename="qysj.xls";
			String mimeType = ServletActionContext.getServletContext().getMimeType(filename);
			//设置文件类型
			response.setContentType(mimeType);
			//content-disposition:指定客户端打开文件的方式
			response.setHeader("content-disposition", "attachment;filename="+filename);
			
			workbook.write(response.getOutputStream());
		
		}catch(Exception e){
			e.printStackTrace();
		}
		
		//本项目  业务中的 导出
		/*try{
			//1.查询所有数据
			List<Area> areas  = new ArrayList<Area>();
			for (int i = 0; i < areas.size(); i++) {
				
			}
			
		}catch(Exception e){
			e.printStackTrace();
		}*/
		
		return NONE;
	}
	
	
	
	
	
	
	
	//属性驱动 获得 分页查询的数据
	private int page;
	private int rows;
	public void setPage(int page) {
		this.page = page;
	}

	public void setRows(int rows) {
		this.rows = rows;
	}
	
	//分页 按条件查询   区域信息
	@Action(value="area_pageQuery",results={@Result(name="success",type="json")})
	public String pageQuery(){
		//调用service 层完成 业务操作
		Page<Area> pageData =   areaServcie.pageQuery(page,rows,area);
		//将返回的数据 封装成固定格式的 json
		Map<String ,Object> result = new HashMap<String,Object>();
		result.put("total", pageData.getTotalElements());
		result.put("rows", pageData.getContent());
		//通过Struts-plugin插件 将数据以json形式返回页面    即压入栈顶即可
		ActionContext.getContext().getValueStack().push(result);
		return SUCCESS;
	}
	
	
	//添加区域信息
	@Action(value="area_save",results={@Result(name="success",location="./pages/base/area.html",type="redirect")})
	public String save(){
		areaServcie.save(area);
		return SUCCESS;
	}
	
	
	//属性驱动   获得页面需要删除的 区域的ids
	private String ids;
	public void setIds(String ids) {
		this.ids = ids;
	}
	//删除区域信息
	@Action(value="area_delBatch",results={@Result(name="success",location="./pages/base/area.html",type="redirect")})
	public String delBatch(){
		//按,分割ids   得到id的数组,直接传数组进行操作
		String[] idArray = ids.split(",");
		//调用业务层 批量删除
		areaServcie.delBatch(idArray);
		return SUCCESS;
	}
	

	/**
	 * 查询所有 区域信息
	 * @return
	 */
	@Action(value="area_findAll",results={@Result(name="success",type="json")})
	public String findAll(){
		List<Area> areas =  areaServcie.findAll();
		ActionContext.getContext().getValueStack().push(areas);
		return SUCCESS;
	}
	
	

}
